#include "windows.h"
#include "tchar.h"
#include "util.h"
//#include <stdio.h>      
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
//#include <time.h>
#include <ctype.h>

HANDLE GetHInst(void);

HHOOK FAR PASCAL InstallCbtHook(void);

LPTSTR WINAPI zap(LPTSTR in_str, int str_len)
{
    LPTSTR ptr = (in_str + (str_len-1));
    if (str_len == '\0') return NULL;
    if (*ptr != ' ') {
        *ptr = '\0';
        return in_str;
    }
    while (ptr >= in_str)
    {
        if (*ptr != ' ') break;
        ptr--;
    }
    if (ptr < in_str) *(in_str) = '\0';
    else *(ptr+1) = '\0';            
    return in_str;
}

void WINAPI StripNull(LPTSTR str, int size)
{
    LPTSTR ptr;
    
    for (ptr = str; ptr <= (str + size); ptr++) {
        if (*ptr == '\0') {
            *ptr = ' ';
            return;
        }
    }
}

//copy from c string to cobol buffer 
void WINAPI CobCopy(LPTSTR dest, LPCTSTR src, int size)
{ 
	MEMSET(dest, ' ', size);
  lstrcpy(dest, src);
  dest[lstrlen(dest)] = ' ';
/*
#ifdef _WIN32
	memset(dest, ' ', size);
  strcpy(dest, src);
  dest[strlen(dest)] = ' ';
#else
	_fmemset(dest, ' ', size);
  lstrcpy(dest, src);
  dest[_fstrlen(dest)] = ' ';
#endif
	*/
}

LPTSTR WINAPI CobToC(LPTSTR dest, LPTSTR src, int size)
{
	STRNCPY(dest, src, size);
//#ifdef _WIN32
//    strncpy(dest, src, size);
//#else
//    _fstrncpy(dest, src, size);
//#endif
    dest[size] = ' ';
    zap(dest, size+1);
    return dest;
}

int WINAPI CentredMessageBox(HWND hwnd, LPTSTR lpszMess, LPTSTR lpszTitle, UINT fuStyle)
{
#ifdef UNDER_CE
		return MessageBox(hwnd, lpszMess, lpszTitle, fuStyle);
#else	
	int nRet;
	HHOOK hHook;           
	HWND hwndParent;
	
	if (hwnd == NULL)
		return MessageBox(hwnd, lpszMess, lpszTitle, fuStyle);

	//jd 2/3/98 - stop hang if parent window is iconic
	//find top level window
	while ((hwndParent = GetParent(hwnd)) != NULL)
		hwnd = hwndParent;
	if (IsIconic(hwnd))
		return MessageBox(hwnd, lpszMess, lpszTitle, fuStyle);

	hHook = InstallCbtHook();
	nRet = MessageBox(hwnd, lpszMess, lpszTitle, fuStyle);
	UnhookWindowsHookEx(hHook);
	return nRet;
#endif
}

#ifndef UNDER_CE
HHOOK FAR PASCAL InstallCbtHook()
{
	FARPROC fp;
	HHOOK hHook;
	HANDLE hInst;
	#ifdef _WIN32
	DWORD dwThreadId;
	#else
	HTASK hTask;
	#endif
	
	hInst = GetHInst();
	fp = GetProcAddress(hInst, (LPCSTR)"HookProc");
	if (fp == NULL)
	{
		return FALSE;
	}

	#ifdef _WIN32
 	dwThreadId = GetCurrentThreadId();
	#else
	hTask = GetCurrentTask();
	if (hTask == NULL)
	{
		return FALSE;
	}
	#endif

	#ifdef _WIN32
	hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC)fp, hInst, dwThreadId);
	#else
	hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC)fp, hInst, hTask);
	#endif
	
	
//	hTask = GetCurrentTask();
//	if (hTask == NULL)
//	{
//		return FALSE;
//	}
//	hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC)fp, GetHInst(), hTask);
	if (hHook == NULL)
	{                          
		return FALSE;
	}
	return hHook;
}                                                           

#define WIDTH(x) (x.right - x.left)
#define HEIGHT(y) (y.bottom - y.top)

DWORD CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
	RECT rc1, rc2;
	int x,y;
	
	if (code >= 0)
	{
		if (code == HCBT_ACTIVATE)
		{
			if (GetWindowLong((HWND)wParam, GWL_STYLE) & WS_POPUP)
			{
				GetWindowRect((HWND)wParam, (LPRECT)&rc1);	
				GetWindowRect(GetParent((HWND)wParam), (LPRECT)&rc2);	
				x = ((WIDTH(rc2) - WIDTH(rc1)) / 2) + rc2.left;
				y = ((HEIGHT(rc2) - HEIGHT(rc1)) / 2) + rc2.top;
				SetWindowPos((HWND)wParam, NULL, x, y, 0, 0,
					SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
			}
		}
	}
	return 0;
}
#endif

//centers a modal dialog in its parent window
void WINAPI CenterDialog(HWND hdlg)
{
	RECT rc1, rc2;
	int x,y;

#ifndef UNDER_CE
	if (IsIconic(GetParent(hdlg)))
		ShowWindow(GetParent(hdlg), SW_SHOWNORMAL);
#endif
	GetWindowRect(hdlg, (LPRECT)&rc1);
	GetWindowRect(GetParent(hdlg), (LPRECT)&rc2);
	x = ((RCWIDTH(rc2) - RCWIDTH(rc1)) / 2) + rc2.left;
	y = ((RCHEIGHT(rc2) - RCHEIGHT(rc1)) / 2) + rc2.top;
	SetWindowPos(hdlg, NULL, x, y, 0, 0,
		SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
}

void WINAPI CenterDialogOnScreen(HWND hdlg)
{
	RECT rc1, rc2;
	int x,y;

	GetWindowRect(hdlg, (LPRECT)&rc1);
//	GetWindowRect(GetDesktopWindow(), (LPRECT)&rc2);
	SetRect((LPRECT)&rc2, 0,0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
	x = ((RCWIDTH(rc2) - RCWIDTH(rc1)) / 2) + rc2.left;
	y = ((RCHEIGHT(rc2) - RCHEIGHT(rc1)) / 2) + rc2.top;
	SetWindowPos(hdlg, NULL, x, y, 0, 0,
		SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
}

void WINAPI Paint3dFrame(HDC hdc, LPRECT lprc, BOOL bIndent)
{ 
	HBRUSH hbr, hbrOld;
	COLORREF clr;
	RECT rc = *lprc;

	if (bIndent)
	{
		hbr = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
		hbrOld = SelectObject(hdc, hbr);
		PatBlt(hdc, rc.left, rc.top, RCWIDTH(rc) - 1, 1, PATCOPY);  	
		PatBlt(hdc, rc.left, rc.top + 1, 1, RCHEIGHT(rc) - 2, PATCOPY);
		SelectObject(hdc, hbrOld);
		DeleteObject(hbr);  	
	  	
		clr = GetSysColor(COLOR_BTNFACE);
		hbr = CreateSolidBrush(RGB(GetRValue(clr)+20, GetGValue(clr)+20, GetBValue(clr)+20));
		hbrOld = SelectObject(hdc, hbr);
		PatBlt(hdc, rc.left + 1, rc.bottom - 2, RCWIDTH(rc) - 3, 1, PATCOPY);  	
		PatBlt(hdc, rc.right - 2, rc.top + 1, 1, RCHEIGHT(rc) - 2, PATCOPY);
		SelectObject(hdc, hbrOld);
		DeleteObject(hbr);  	
	  	
		PatBlt(hdc, rc.left + 1, rc.top + 1, RCWIDTH(rc) - 3, 1, BLACKNESS);  	
		PatBlt(hdc, rc.left + 1, rc.top + 2, 1, RCHEIGHT(rc) - 4, BLACKNESS);
	  	
		PatBlt(hdc, rc.left, rc.bottom - 1, RCWIDTH(rc), 1, WHITENESS);  	
		PatBlt(hdc, rc.right - 1, rc.top, 1, RCHEIGHT(rc) - 1, WHITENESS);
	}
	else
	{
		PatBlt(hdc, rc.left, rc.top, RCWIDTH(rc) - 1, 1, WHITENESS);  	
		PatBlt(hdc, rc.left, rc.top + 1, 1, RCHEIGHT(rc) - 2, WHITENESS);
	  	
		hbr = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
		hbrOld = SelectObject(hdc, hbr);
		PatBlt(hdc, rc.left + 1, rc.bottom - 2, RCWIDTH(rc) - 3, 1, PATCOPY);  	
		PatBlt(hdc, rc.right - 2, rc.top + 1, 1, RCHEIGHT(rc) - 2, PATCOPY);
//		PatBlt(hdc, rc.left, rc.bottom - 1, RCWIDTH(rc), 1, PATCOPY);  	
//		PatBlt(hdc, rc.right - 1, rc.top, 1, RCHEIGHT(rc) - 1, PATCOPY);
		SelectObject(hdc, hbrOld);
		DeleteObject(hbr);  	
	  	
		clr = GetSysColor(COLOR_BTNFACE);
		hbr = CreateSolidBrush(RGB(GetRValue(clr)+20, GetGValue(clr)+20, GetBValue(clr)+20));
		hbrOld = SelectObject(hdc, hbr);
		PatBlt(hdc, rc.left + 1, rc.top + 1, RCWIDTH(rc) - 3, 1, PATCOPY);  	
		PatBlt(hdc, rc.left + 1, rc.top + 2, 1, RCHEIGHT(rc) - 4, PATCOPY);
		SelectObject(hdc, hbrOld);
		DeleteObject(hbr);  	
	  	
		PatBlt(hdc, rc.left, rc.bottom - 1, RCWIDTH(rc), 1, BLACKNESS);  	
		PatBlt(hdc, rc.right - 1, rc.top, 1, RCHEIGHT(rc) - 1, BLACKNESS);
	}
}                                                            

int WINAPI GetWindowHeight(HWND hwnd)
{
	RECT rc;
	GetWindowRect(hwnd, (LPRECT)&rc);
	return (rc.bottom - rc.top);
}

int WINAPI GetWindowWidth(HWND hwnd)
{
	RECT rc;
	GetWindowRect(hwnd, (LPRECT)&rc);
	return (rc.right - rc.left);
}

BOOL WINAPI StrMatch(LPTSTR lpsz1, LPTSTR lpsz2)
{
	LPTSTR lp1, lp2;
	
	lp1 = lpsz1;
	lp2 = lpsz2;
	if (*lp2 == '\0')
		return TRUE;
	while (*lp1)
	{
		if (*lp2 == *lp1)
			*lp2++;
		else
			return FALSE;
		if (*lp2 == '\0')
			return TRUE;
		lp1++;		
	}
	return FALSE;
}

BOOL WINAPI StrMatchNoCase(LPTSTR lpsz1, LPTSTR lpsz2)
{
	LPTSTR lp1, lp2;
	
	lp1 = lpsz1;
	lp2 = lpsz2;
	if (*lp2 == '\0')
		return TRUE;
	while (*lp1)
	{
		#ifdef UNICODE
			if (towupper(*lp2) == towupper(*lp1))
		#else
			if (toupper(*lp2) == toupper(*lp1))
		#endif
			*lp2++;
		else
			return FALSE;
		if (*lp2 == '\0')
			return TRUE;
		lp1++;		
	}
	return FALSE;
}

#ifdef UNDER_CE
HANDLE GlobalAlloc(int n, DWORD dw)
{
	void* p = malloc(dw);
	if (p == NULL)
		return p;
	memset(p, 0, dw);	
	return (HANDLE)p;
}

void* GlobalLock(HANDLE h)
{
	return (void*)h;
}

BOOL GlobalUnlock(HANDLE h)
{
	return TRUE;
}

HANDLE GlobalFree(HANDLE h)
{
	free((void*)h);
	return NULL;
}
#endif

void Compress(LPSTR pDataIn, int cbIn, LPSTR pDataOut, LPINT pcbOut)
{
	LPSTR ptr1;
	LPSTR ptr2;
	LPSTR ptr3;
	int nSpaces = 0;

	ptr3 = pDataOut;
	for (ptr2 = ptr1 = pDataIn; ptr1 < (pDataIn+cbIn); ptr1++)
	{
		if (*ptr1 == '\0')
			break;
		if (*ptr1 == ' ')
		{
			nSpaces++;
			continue;
		}
		else
		{
			if (nSpaces > 0)
			{
				*ptr3++ = 0x01;
				*((short*)ptr3) = (short)nSpaces;
				ptr3 += sizeof(short);
				nSpaces = 0;
			}
			*ptr3++ = *ptr1;
		}
	}
	*pcbOut = (ptr3 - pDataOut);
}

void Uncompress(LPSTR pDataIn, int cbIn, LPSTR pDataOut, LPINT pcbOut)
{
	LPSTR ptr1;
	LPSTR ptr3;
	int nSpaces;

	ptr3 = pDataOut;
	for (ptr1 = pDataIn; ptr1 < (pDataIn+cbIn); ptr1++)
	{
		if (*ptr1 == 0x01)
		{
			ptr1++;
			nSpaces = (*(short*)ptr1);
			memset(ptr3, ' ', nSpaces);
			ptr3 += nSpaces;
			ptr1 += sizeof(short);
		}
		*ptr3++ = *ptr1;
	}
	*pcbOut = (ptr3 - pDataOut);
}

#ifdef WIN32
LPTSTR StrEllipsis(LPTSTR lpszIn, LPTSTR lpszOut, int cx, HDC hDC)
{
	//truncates a string and appends ellipsis if string is too
	//large to fit in cx
	TCHAR szEllipsis[] = "...";
	SIZE sz;
	int cxEllipsis;

	if (lpszIn[0] == '\0')
	{
		lpszOut[0] = '\0';
		return lpszOut;
	}

	GetTextExtentPoint32(hDC, (LPTSTR)szEllipsis, lstrlen((LPTSTR)szEllipsis), &sz);
	cxEllipsis = sz.cx;
	if (cxEllipsis > cx)
	{
		lstrcpy(lpszOut, szEllipsis);
		return lpszOut;
	}

	lstrcpy(lpszOut, lpszIn);
	GetTextExtentPoint32(hDC, lpszOut, lstrlen(lpszOut), &sz);
	if (sz.cx <= cx)
		return lpszOut;

	//try knocking chars off string one at a time, until string fits
	for (;;)
	{
		lpszOut[lstrlen(lpszOut)-1] = '\0';
		GetTextExtentPoint32(hDC, (LPTSTR)lpszOut, lstrlen(lpszOut), &sz);
		if ((sz.cx + cxEllipsis) <= cx)
		{
			lstrcat(lpszOut, szEllipsis);
			return lpszOut; 
		}
	}
}
#endif

int WINAPI GetUniqueId()
{
	static int id = 0;
	return id++;
}
